﻿Imports System
Imports System.Globalization
Imports System.Reflection
Imports System.Workflow.ComponentModel.Compiler
Imports System.Workflow.ComponentModel.Design

Namespace System.Workflow.ComponentModel
    Friend Class BindHelpers
        ' Methods
        Friend Shared Function GetAccessType(ByVal serviceProvider As IServiceProvider, ByVal validationContext As PropertyValidationContext) As AccessTypes
            Dim read As AccessTypes = AccessTypes.Read
            If TypeOf validationContext.Property Is PropertyInfo Then
                Return Helpers.GetAccessType([TryCast](validationContext.Property,PropertyInfo), validationContext.PropertyOwner, serviceProvider)
            End If
            If TypeOf validationContext.Property Is DependencyProperty Then
                Dim propertyOwner As IDynamicPropertyTypeProvider = [TryCast](validationContext.PropertyOwner,IDynamicPropertyTypeProvider)
                If (Not propertyOwner Is Nothing) Then
                    read = propertyOwner.GetAccessType(serviceProvider, DirectCast(validationContext.Property, DependencyProperty).Name)
                End If
            End If
            Return read
        End Function

        Friend Shared Function GetBaseType(ByVal serviceProvider As IServiceProvider, ByVal validationContext As PropertyValidationContext) As Type
            Dim propertyType As Type = Nothing
            If TypeOf validationContext.Property Is PropertyInfo Then
                Return Helpers.GetBaseType([TryCast](validationContext.Property,PropertyInfo), validationContext.PropertyOwner, serviceProvider)
            End If
            If TypeOf validationContext.Property Is DependencyProperty Then
                Dim property As DependencyProperty = [TryCast](validationContext.Property,DependencyProperty)
                If ([property] Is Nothing) Then
                    Return propertyType
                End If
                If (propertyType Is Nothing) Then
                    Dim propertyOwner As IDynamicPropertyTypeProvider = [TryCast](validationContext.PropertyOwner,IDynamicPropertyTypeProvider)
                    If (Not propertyOwner Is Nothing) Then
                        propertyType = propertyOwner.GetPropertyType(serviceProvider, [property].Name)
                    End If
                End If
                If (propertyType Is Nothing) Then
                    propertyType = [property].PropertyType
                End If
            End If
            Return propertyType
        End Function

        Friend Shared Function GetMatchedPropertyInfo(ByVal memberType As Type, ByVal aryArgName As String(), ByVal args As Object()) As PropertyInfo
            If (memberType Is Nothing) Then
                Throw New ArgumentNullException("memberType")
            End If
            If (aryArgName Is Nothing) Then
                Throw New ArgumentNullException("aryArgName")
            End If
            If (args Is Nothing) Then
                Throw New ArgumentNullException("args")
            End If
            Dim infoArray5 As MemberInfo()() = New MemberInfo()(2  - 1) {}
            infoArray5(0) = memberType.GetDefaultMembers
            Dim infoArray As MemberInfo()() = infoArray5
            If memberType.IsArray Then
                Dim member As MemberInfo() = memberType.GetMember("Get")
                Dim infoArray3 As MemberInfo() = memberType.GetMember("Set")
                Dim info As PropertyInfo = New ActivityBindPropertyInfo(memberType, [TryCast](member(0),MethodInfo), [TryCast](infoArray3(0),MethodInfo), String.Empty, Nothing)
                infoArray(1) = New MemberInfo() { info }
            End If
            Dim i As Integer
            For i = 0 To infoArray.Length - 1
                If (Not infoArray(i) Is Nothing) Then
                    Dim infoArray4 As MemberInfo() = infoArray(i)
                    Dim info2 As MemberInfo
                    For Each info2 In infoArray4
                        Dim propertyInfo As PropertyInfo = [TryCast](info2,PropertyInfo)
                        If ((Not propertyInfo Is Nothing) AndAlso BindHelpers.MatchIndexerParameters(propertyInfo, aryArgName, args)) Then
                            Return propertyInfo
                        End If
                    Next
                End If
            Next i
            Return Nothing
        End Function

        Friend Shared Function GetMemberType(ByVal memberInfo As MemberInfo) As Type
            Dim info As FieldInfo = [TryCast](memberInfo,FieldInfo)
            If (Not info Is Nothing) Then
                Return info.FieldType
            End If
            Dim info2 As PropertyInfo = [TryCast](memberInfo,PropertyInfo)
            If (Not info2 Is Nothing) Then
                If (Not info2.PropertyType Is Nothing) Then
                    Return info2.PropertyType
                End If
                Return info2.GetGetMethod.ReturnType
            End If
            Dim info4 As EventInfo = [TryCast](memberInfo,EventInfo)
            If (Not info4 Is Nothing) Then
                Return info4.EventHandlerType
            End If
            Return Nothing
        End Function

        Friend Shared Function MatchIndexerParameters(ByVal propertyInfo As PropertyInfo, ByVal argNames As String(), ByVal args As Object()) As Boolean
            If (propertyInfo Is Nothing) Then
                Throw New ArgumentNullException("propertyInfo")
            End If
            If (argNames Is Nothing) Then
                Throw New ArgumentNullException("argNames")
            End If
            If (args Is Nothing) Then
                Throw New ArgumentNullException("args")
            End If
            Dim indexParameters As ParameterInfo() = propertyInfo.GetIndexParameters
            If (indexParameters.Length <> argNames.Length) Then
                Return False
            End If
            Dim i As Integer
            For i = 0 To args.Length - 1
                Dim parameterType As Type = indexParameters(i).ParameterType
                If ((Not parameterType Is GetType(String)) AndAlso (Not parameterType Is GetType(Integer))) Then
                    Return False
                End If
                Try 
                    Dim obj2 As Object = Nothing
                    Dim str As String = argNames(i).Trim
                    If (((parameterType Is GetType(String)) AndAlso str.StartsWith("""", StringComparison.Ordinal)) AndAlso str.EndsWith("""", StringComparison.Ordinal)) Then
                        obj2 = str.Substring(1, (str.Length - 2)).Trim
                    ElseIf (parameterType Is GetType(Integer)) Then
                        obj2 = Convert.ChangeType(str, GetType(Integer), CultureInfo.InvariantCulture)
                    End If
                    If (Not obj2 Is Nothing) Then
                        args.SetValue(obj2, i)
                    Else
                        Return False
                    End If
                Catch obj1 As Object
                    Return False
                End Try
            Next i
            Return True
        End Function

        Friend Shared Function ResolveActivityPath(ByVal refActivity As Activity, ByVal path As String) As Object
            Dim walker As PathWalker
            If (refActivity Is Nothing) Then
                Throw New ArgumentNullException("refActivity")
            End If
            If (path Is Nothing) Then
                Throw New ArgumentNullException("path")
            End If
            If (path.Length = 0) Then
                Throw New ArgumentException(SR.GetString("Error_EmptyPathValue"), "path")
            End If
            Dim value As Object = refActivity
            Dim recursionContext As New BindRecursionContext
            If New PathWalker() { _
                .MemberFound = DirectCast(Delegate.Combine(walker.MemberFound, Function (ByVal sender As Object, ByVal eventArgs As PathMemberInfoEventArgs) 
                    If (value Is Nothing) Then
                        eventArgs.Action = PathWalkAction.Cancel
                    Else
                        Select Case eventArgs.MemberKind
                            Case PathMemberKind.Field
                                Try 
                                    value = [TryCast](eventArgs.MemberInfo,FieldInfo).GetValue(value)
                                Catch exception As Exception
                                    value = Nothing
                                    eventArgs.Action = PathWalkAction.Cancel
                                    If Not refActivity.DesignMode Then
                                        Dim exception2 As TargetInvocationException = [TryCast](exception,TargetInvocationException)
                                        Throw If((Not exception2 Is Nothing), exception2.InnerException, exception)
                                    End If
                                End Try
                                Exit Select
                            Case PathMemberKind.Event
                                Dim memberInfo As EventInfo = [TryCast](eventArgs.MemberInfo,EventInfo)
                                Dim dependencyProperty As DependencyProperty = DependencyProperty.FromName(memberInfo.Name, value.GetType)
                                If ((Not dependencyProperty Is Nothing) AndAlso TypeOf value Is DependencyObject) Then
                                    If [TryCast](value,DependencyObject).IsBindingSet(dependencyProperty) Then
                                        value = [TryCast](value,DependencyObject).GetBinding(dependencyProperty)
                                    Else
                                        value = [TryCast](value,DependencyObject).GetHandler(dependencyProperty)
                                    End If
                                End If
                                Exit Select
                            Case PathMemberKind.Property
                                If [TryCast](eventArgs.MemberInfo,PropertyInfo).CanRead Then
                                    Dim property2 As DependencyProperty = DependencyProperty.FromName(eventArgs.MemberInfo.Name, value.GetType)
                                    If (((Not property2 Is Nothing) AndAlso TypeOf value Is DependencyObject) AndAlso [TryCast](value,DependencyObject).IsBindingSet(property2)) Then
                                        value = [TryCast](value,DependencyObject).GetBinding(property2)
                                    Else
                                        Try 
                                            value = [TryCast](eventArgs.MemberInfo,PropertyInfo).GetValue(value, Nothing)
                                        Catch exception3 As Exception
                                            value = Nothing
                                            eventArgs.Action = PathWalkAction.Cancel
                                            If Not refActivity.DesignMode Then
                                                Dim exception4 As TargetInvocationException = [TryCast](exception3,TargetInvocationException)
                                                Throw If((Not exception4 Is Nothing), exception4.InnerException, exception3)
                                            End If
                                        End Try
                                    End If
                                    Exit Select
                                End If
                                eventArgs.Action = PathWalkAction.Cancel
                                Return
                            Case PathMemberKind.IndexedProperty, PathMemberKind.Index
                                Try 
                                    value = [TryCast](eventArgs.MemberInfo,PropertyInfo).GetValue(value, BindingFlags.GetProperty, Nothing, eventArgs.IndexParameters, CultureInfo.InvariantCulture)
                                Catch exception5 As Exception
                                    value = Nothing
                                    eventArgs.Action = PathWalkAction.Cancel
                                    If Not refActivity.DesignMode Then
                                        Dim exception6 As TargetInvocationException = [TryCast](exception5,TargetInvocationException)
                                        Throw If((Not exception6 Is Nothing), exception6.InnerException, exception5)
                                    End If
                                End Try
                                Exit Select
                        End Select
                        If ((TypeOf value Is ActivityBind AndAlso Not eventArgs.LastMemberInThePath) AndAlso (Not BindHelpers.GetMemberType(eventArgs.MemberInfo) Is GetType(ActivityBind))) Then
                            Do While TypeOf value Is ActivityBind
                                Dim bind As ActivityBind = [TryCast](value,ActivityBind)
                                If recursionContext.Contains(refActivity, bind) Then
                                    Throw New InvalidOperationException(SR.GetString("Bind_ActivityDataSourceRecursionDetected"))
                                End If
                                recursionContext.Add(refActivity, bind)
                                value = bind.GetRuntimeValue(refActivity)
                            Loop
                        End If
                    End If
                End Function), EventHandler([Of] PathMemberInfoEventArgs)) _
            }.TryWalkPropertyPath(refActivity.GetType, path) Then
                Return value
            End If
            Return Nothing
        End Function

    End Class
End Namespace

